
#ifndef	__FECAB_CLIENT_HPP_2010__
#define	__FECAB_CLIENT_HPP_2010__

#include <string>
#include <utility>
#include <vector>

#include <boost/thread/mutex.hpp>


namespace	fecab	{
namespace	client	{

class	Broker;

struct	kv_type
{
	std::string	key;
	std::string	value;
	/*
	 * status code for key-value operation :
	 *   100 -- NOT-FOUND for GET operation only
	 *   200 -- operate (PUT/GET/ERASE) successfully
	 *   400 -- DB operate (PUT/GET/ERASE) failure
	 *   405 -- LUA script operate failure
	 *   500 -- fatal service error
	 */
	u_int32_t	status;
};


class	Client
{

public	:
	Client( const char* config_server, const char* app_conf_id );
	Client( const char* app_config_filename );

	~Client();

public	:
	int   put( const std::string& table, 
			   const std::string& key, 
			   const std::string& data );

	int   get( const std::string& table, 
			   const std::string& key,
			         std::string& data );

	int   erase( const std::string& table, 
			     const std::string& key );

public	:
	int	sput( const std::string& table,
			  const std::string& key,
    		  const std::string& data_in,
			  const std::string& script,
			  const std::string& data_crumb,
			        std::string& data_out );

	/**
	 * put multiple Key-Value pairs into database with supported (LUA) script function
	 *
	 * @param table    name of table
	 * @param kvs_in   list of key-value pairs to put
	 * @param script   name of (LUA) script function
	 * @param crumb    user data for script function
	 * @param kvs_out  list of operation status for each key-value pairs
	 *
	 * @return size of kvs_out
	 */
	int	smput( const std::string& table,
		 	   const std::vector< kv_type >& kvs_in,
			   const std::string& script,
			   const std::string& crumb,
		 	         std::vector< kv_type >& kvs_out );

	
public	:
	int   put( const char* table, 
			   const char* key,  u_int32_t key_len,
			   const char* data, u_int32_t data_len );

	int   get( const char* table, 
			   const char* key,  u_int32_t key_len,
			   const char* data, u_int32_t data_len );

	int   erase( const char* table, 
			     const char* key,  u_int32_t key_len );

public	:
	const std::string&	last_error( void ) const { return _error; }

private	:
	int		parseAppConfig( const char* filename );
	int		parseLogConfig( const char* filename );

	int		initialize();
	int		finalize();

	int		getSid();

private	:
	Broker*	getBrokerByTable( const char* table );

	int		callBroker( Broker* broker_p, const std::string& request, std::string& response );

private	:
	typedef	std::string	host_type;
	typedef	std::string	port_type;
	typedef	std::pair< host_type, port_type >	server_address_type;
	typedef	std::vector< server_address_type >	server_address_list_type;
	server_address_list_type	server_address_list;
	
	typedef	std::vector< Broker* >	server_list_type;
	server_list_type	server_list;

	int		_current_sid;
	boost::mutex	_current_sid_mutex;

	std::string	_error;

};	// class Client


}	// namespace client
}	// namespace fecab

#endif	// __FECAB_CLIENT_HPP_2010__

